package mts;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;

import mts.common.CommonSettings;
import mts.messages.ElevatorControllerInitMessage;
import mts.messages.EventTimeStampMessage;
import mts.messages.Message;

import org.apache.log4j.Logger;

/**
 * No realtime priority is needed for this class
 * 
 * @author Nick
 * 
 */
public class ElevatorControllerInternalConnection extends Thread {
	private static final Logger log = Logger.getLogger(ElevatorControllerInternalConnection.class);

	private Socket socket;
	private ProjectControllerManager manager;
	private byte car;
	private boolean shouldTerminate = false;
	
	public byte getCar() {
		return car;
	}
	
	private ElevatorControllerView elevatorControllerView;
	
	public ElevatorControllerInternalConnection(ProjectControllerManager manager, Socket socket) {
		this.socket = socket;
		this.manager = manager;
		
		ElevatorControllerInitMessage initMessage = (ElevatorControllerInitMessage)receiveMessage();
		
		this.car = initMessage.getCar();
				
		try {
			Thread.sleep(700);
		} catch (InterruptedException e) {
			log.error("Couldn't sleep", e);
		}
		
		this.elevatorControllerView = this.manager.addView(this);
		start();		
	}

	private ArrayList<NewEventTimestampListener> onNewEventTimestampListeners = new ArrayList<NewEventTimestampListener>();
	
	public void addOonNewEventTimestampListener(NewEventTimestampListener listener) {
		synchronized (onNewEventTimestampListeners) {
			onNewEventTimestampListeners.add(listener);
		}
	}
	
	public void removeOnNewEventTimestampListener(
			NewEventTimestampListener listener) {
		synchronized (onNewEventTimestampListeners) {
			onNewEventTimestampListeners.remove(listener);
		}
		
	}
	
	
	@SuppressWarnings("unchecked")
	@Override
	public void run() {			
		
//		// TODO move me to a better location
//		StatusMessage currentStatusmessage = manager.getGroupDispatcher().getElevatorControllerStatusMessage(car);
//		if (currentStatusmessage != null) {
//			elevatorControllerView.updateStatus(currentStatusmessage);		
//		}
		
		while (!shouldTerminate) {
			Message message = receiveMessage();
			if (!(message instanceof EventTimeStampMessage)) {
				log.error("Message was not an event time stamp message");
			} else {
				EventTimeStampMessage eventTimeStampMessage = (EventTimeStampMessage)message;			
				
				for (NewEventTimestampListener listener: (ArrayList<NewEventTimestampListener>)onNewEventTimestampListeners.clone()) {
					listener.addEventTimeStamp(eventTimeStampMessage);
				}
			}
		}
		
		
	}
	

	public void sendMessage(Message message) {
		
		if (socket == null) {
			log.error("Cannot sendMessage - No socket found for Car");
			return;
		}
		try {			
			OutputStream out = socket.getOutputStream();
			byte[] data = message.serialize();
			log.info("Sending message to client - " + new String(data));
			out.write(data);
			out.flush();
		} catch (IOException ex) {
			log.error("Could not send message to client. ", ex);
			this.manager.removeView(elevatorControllerView);
			shouldTerminate = true;
		}
	}
	
	public Message receiveMessage() {
		try {
			InputStream in = socket.getInputStream();
			
			byte[] data = new byte[CommonSettings.MAX_PACKET_SIZE];
			int length = in.read(data);
			
			if (length == -1) {
				log.warn("Could not receive message from client. Removing Car Panel. ");
				this.manager.removeView(elevatorControllerView);
				shouldTerminate = true;
				return null;
			}
			
			log.info("Receiving message from client - " + new String(data, 0, length));
			
			return Message.deserialize(data);
			
			
			
		} catch (IOException ex) {
			log.warn("Could not receive message from client. ", ex);
			
			return null;
		}
		
	}



	
	
}